#include "funs.hpp"
#include <iostream>
#include "arpa/inet.h"
#include "json.hpp"
#include "public.hpp"

using namespace std;
User g_curUser;
vector<Group> g_groups;

using json = nlohmann::json;
unordered_map<string, string> commandsMap = {
    {"help"s, "show all commands"s},
    {"chat"s, "format chat:toid:message"s},
    {"addFriend"s, "format addFriend:friendId"s},
    {"addGroup"s, "format addGroup:groupId"s},
    {"createGroup"s, "format createGroup:groupName"s},
    {"groupChat"s, "format groupChat:groupId:message"s},
    {"showAllGroups", "show all groups format: sg"},
    {"logout", "logout"}};

unordered_map<string, CommandsHanlder> commandsHanlders = {
    {"help"s, help},          {"chat"s, chat},
    {"logout"s, logout},      {"addFriend"s, addFriend},
    {"addGroup"s, addGroup},  {"createGroup"s, createGroup},
    {"logout", logout},
    {"groupChat"s, groupChat}};

void showMainMenu(int cfd) {
    // 打印登录之后的菜单
    cout << "=============================" << endl;
    for (auto it : commandsMap) {
        cout << "==== " << it.first << " : " << it.second << endl;
    }
    while (1) {
        string buff = "";
        getline(cin, buff);
        int pos = buff.find(":");
        if (pos == -1) {
            if (buff == "sg") {
                showGroupsInfo();
            } else if (buff == "logout") {
                logout(cfd, "");
                break;
            } else
                help(cfd);
            continue;
        }
        string cmd = buff.substr(0, pos);
        auto it = commandsHanlders.find(cmd);
        if (it == commandsHanlders.end()) {
            cout << "Invalid command!" << endl;
            continue;
        }
        it->second(cfd, string(buff.begin() + pos + 1, buff.end()));
    }
}
void help(int cfd, string s) {
    cout << "=============================" << endl;
    for (auto it : commandsMap) {
        cout << it.first << " : " << it.second << endl;
    }
}
void chat(int cfd, string buff) {
    int pos = buff.find(":");
    if (pos == -1) {
        cout << "Invalid command!" << endl;
        return;
    }
    string id = buff.substr(0, pos + 1);
    int toid = stoi(id);
    string msg = buff.substr(pos + 1);
    // {"msgId": 2, "id": 22, "name": "Zhang San", "toId": 22, "msg": "hello
    // world"}
    json req;
    req["msgId"] = EnMsHandler::SEND_MSG;
    req["userId"] = g_curUser.getId();
    req["toId"] = toid;
    req["name"] = g_curUser.getName();
    req["msg"] = msg;
    string s = req.dump();
    sendMsg(cfd, s.c_str(), s.size());

}
void logout(int cfd, string buff) {
    json req;
    req["msgId"] = EnMsHandler::LOGINOUT;
    req["userId"] = g_curUser.getId();
    string s = req.dump();
    sendMsg(cfd, s.c_str(), s.size());
    cout << "good bye " << g_curUser.getName() << endl;
}
void printCurDateTime() {
    time_t now = time(0);
    tm* ltm = localtime(&now);
    cout << 1900 + ltm->tm_year << "-" << 1 + ltm->tm_mon << "-" << ltm->tm_mday
         << " ";
    cout << ltm->tm_hour << ":" << ltm->tm_min << ":" << ltm->tm_sec << "\t";
}
void addFriend(int cfd, std::string s) {
    json req;
    req["msgId"] = EnMsHandler::ADD_FRIEND;
    req["userId"] = g_curUser.getId();
    req["friendId"] = stoi(s);
    auto msg = req.dump();
    sendMsg(cfd, msg.c_str(), msg.size());
}
void addGroup(int cfd, std::string s) {
    json req;
    int groupId = stoi(s);
    int userid = g_curUser.getId();
    req["msgId"] = EnMsHandler::ADD_GROUP;
    req["groupId"] = groupId;
    req["userId"] = userid;
    auto msg = req.dump();
    sendMsg(cfd, msg.c_str(), msg.size());
}
void createGroup(int cfd, std::string s) {
    int pos = s.find(":");
    if (pos == -1) {
        cout << "Invalid command!" << endl;
        return;
    }
    json req;
    req["msgId"] = EnMsHandler::CREATE_GROUP;
    req["userid"] = g_curUser.getId();
    req["groupname"] = string(s.begin(), s.begin() + pos);
    req["groupdesc"] = string(s.begin() + pos + 1, s.end());
    auto msg = req.dump();
    sendMsg(cfd, msg.c_str(), msg.size());

}
void groupChat(int cfd, std::string s) {
    const int pos = s.find(":");
    const int groupId = stoi(s.substr(0, pos));
    const string msg = s.substr(pos + 1);
    json req;
    req["msgId"] = EnMsHandler::GROUP_CHAT;
    req["name"] = g_curUser.getName();
    req["userId"] = g_curUser.getId();
    req["groupId"] = groupId;
    req["msg"] = msg;
    auto msgStr = req.dump();
    sendMsg(cfd, msgStr.c_str(), msgStr.size());
}
int sendMsg(int cfd, const char* msg, int len) {
    int size = 0;
    int l = 0;
    while (l = send(cfd, msg + size, len - size, 0)) {
        if (size == -1) {
            perror("send error");
            return -1;
        }
        size += l;
    }
    return size;
}
void showGroupsInfo() {
    // 打印群组信息以及群员列表，在线状态
    printf("==========Group List=========\n");
    printf("groupId\tgroupName\tgroupDesc\n");
    for (auto group : g_groups) {
        printf("%d\t%s\t%s\n", group.GetId(), group.GetName().c_str(),
               group.GetDesc().c_str());
        // 展示群组成员
        printf("Group Users:\n");
        for (auto user : group.GetUsers()) {
            printf("%d\t%s\t%s\t%s\n", user.getId(), user.getName().c_str(),
                   user.getState().c_str(), user.getRole().c_str());
        }
    }
    printf("=============================\n");
}